/* 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

Title : com.Angaliwa.Cam
Author : Dave Jansen -- Zenitum
URL : http://www.zenitum.com/

Description : The Webcam module of Angaliwa,
			  which allows you to easily connect and use
			  webcam(s).

Created : May 1st, 2009

History		: v1.2.090811 Completely rewrote most of the 
			  module to support the new Angaliwa modules.

			  v1.1 Undocumented update.
			  
			  v1.0.090301 Initial version

Version: 1.2
Compatibility: 1.2

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
*/

package com.Angaliwa
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.events.TimerEvent;
	import flash.media.Camera;
	import flash.media.Microphone;
	import flash.media.Video;
	import flash.net.NetStream;
	import flash.utils.Timer;
	
	import mx.core.UIComponent;
	
	public class Cam
	{
		public var daisyChain:DaisyChain = new DaisyChain(this);
		public var settings:Settings = new Settings(this);
		
		private var cam:Camera;
		private var mic:Microphone;
		
		private var cams:Array;
		private var mics:Array;
		
		// For the Attach method
		public static var cans:Object = [];
		public static var timer:Timer;
		
		/*
		 * Summary:      	Initializes the new webcam instance.
		 					Originally called 'Set'.
		 * Return:       	Void
		 * Version:   	 	1.2
		 * Compatibility:	1.2
		 */
		public function Cam(camera:String=undefined, customSettings:Object=undefined, microphone:int=undefined){
			cam = Camera.getCamera(camera);
			
			if(cam){
				// Set the default settings
				settings.setDefaults({width: 320, height: 240,
									  framerate: 15, bitrate: 40000, quality: 80,
									  keyFrameInterval: 5, 
									  motionLevel: 4, motionLevelTimeout: 2000,
									  enableSound: false,
									  soundRate: 11, soundGain: 70});
				
				if(customSettings)
					settings.add(customSettings);
				
				// Set the quality, bitrate, keyFrameInterval and 
				// motionlevel of the camera.
				cam.setMode(settings.get('width'), 
							settings.get('height'), 
							settings.get('framerate'));
				cam.setQuality(settings.get('bitrate'), 
							settings.get('quality'));
				cam.setKeyFrameInterval(settings.get('keyFrameInterval'));
				cam.setMotionLevel(settings.get('motionLevel'), 
							settings.get('motionLevelTimeout'));
				
				if(settings.get('enableSound')){
					mic = Microphone.getMicrophone(microphone);
					
					// Set the rate, gain, etc. of the microphone.
					mic.rate = settings.get('soundRate');
					mic.gain = settings.get('soundGain');
				}
			}
			else{
				/*
					ToDo: A warning/error system needs to be implemented for 
					situations such as these.
				*/
			}
		}
		
		/*
		 * Summary:      	Returns the defined webcam and microphone 
		 					instance, if present. Originally named 'Get'.
		 * Return:       	Object
		 * Version:   	 	1.2
		 * Compatibility:	1.2
		 */
		public function g():Object{
			return {cam:cam,mic:mic};
		}
		
		/*
		 * Summary:      	Attaches a video object to the specified
		 					object.
		 * Return:       	Void
		 * Version:   	 	1.0
		 * Compatibility:	1.0
		 */
		public static function attach(obj:*, video:*, id:String):Boolean{
			var vid:Video = new Video(obj.width, obj.height);
			vid.name = "innerVideo";
			
			// Create a new UIComponent as we can't simply add
			// the video object, for whatever reason.
			var d:UIComponent = new UIComponent();
			d.name = "video";
			
			/*if(video is NetStream){
				if(!Cam.cans[id]){
					vid.attachNetStream(video);
					vid.cacheAsBitmap = true;
					
					Cam.cans[id] = {objects: new Array(obj), can:false, video:video, vid:vid};
					
					//if(!video.hasEventListener(NetStatusEvent.NET_STATUS)){
					video.addEventListener(NetStatusEvent.NET_STATUS, function(e:NetStatusEvent):void{
						if(e.info.code == "NetStream.Buffer.Full" && !Cam.cans[id].can){
							trace(id+': Enabled.');
							Cam.cans[id].can=true;
						}
						
						if(e.info.code == "NetStream.Play.UnpublishNotify"){
							trace(id+': Disabled.');
							Cam.cans[id].can=false;
						}
						
						//trace(id+': '+e.info.code);
					});
					//}
					
					if(!Cam.timer){
						Cam.timer = new Timer(50);
						Cam.timer.addEventListener(TimerEvent.TIMER, Cam.update);
						//Cam.timer.start();
					}
				}
				else{
					trace(id+': Adding another object.');
					Cam.cans[id].objects.push(obj);
				}
			}*/
			if(video is NetStream){
				vid.attachNetStream(video);
				vid.cacheAsBitmap = true;
				
				vid.width = obj.width;
				vid.height= obj.height;
				
				d.addChild(vid);
				obj.addChild(d);
			}
			else if(video is Camera){
				vid.attachCamera(video);
				d.addChild(vid);
				
				// Set the size accordingly.
				vid.width = obj.width;
				vid.height = obj.height;
				
				// Double-confirm the size.
				d.setActualSize(obj.width, obj.height);
				
				obj.addChild(d);
			}
			else{ 
				return false;
			}
			
			return true;
		}
		
		public static function detach(obj:*, video:*):void{
			if(video is NetStream){
				if(Cam.cans[video]){
					var n:Array = new Array();
					
					for(var i:int=0; i < Cam.cans[video].objects.length; i++){
						if(Cam.cans[video].objects[i] != obj)
							n.push(Cam.cans[video].objects[i]);
					}
					
					Cam.cans[video].objects = n;
				}
			}
		}
		
		public static function update(e:TimerEvent=undefined):void{
			for(var c:String in Cam.cans){
				if(Cam.cans[c].can && Cam.cans[c].vid){
					trace(c+': Showing..');
					
					for(var i:int=0; i < Cam.cans[c].objects.length; i++){
						var itm:* = Cam.cans[c].objects[i];
						
						if(itm && itm.width > 0){
							Cam.cans[c].vid.width=itm.width;
							Cam.cans[c].vid.height=itm.height;
							
							var bmd:BitmapData = new BitmapData(itm.width, itm.height);
							bmd.draw(Cam.cans[c].vid);
							
							var bm:Bitmap = new Bitmap(bmd);
							var ui:UIComponent = new UIComponent();
							ui.addChild(bm);
							
							itm.removeAllChildren();
							itm.addChild(ui);
						}
					}
				}
				else{
					trace(c+': Waiting for the go-ahead..');
				}
			}
		}
		
		
		/*** IN DEVELOPMENT ***/
		
		
		/*
		 * Summary:      	Returns an Array with all available webcams.
		 * Return:       	Array
		 * Version:   	 	1.0
		 * Compatibility:	1.0
		 */
		public function getAllWebcams():Array{
			if(!cams) cams = Camera.names;
			
			return cams;
		}
		
		/*
		 * Summary:      	Returns an Array with all available microphones.
		 * Return:       	Array
		 * Version:   	 	1.0
		 * Compatibility:	1.0
		 */
		public function getAllMicrophones():Array{
			if(!mics) mics = Microphone.names;
			
			return mics;
		}
		
		/*
		 * Summary:      	Shows all webcams in a horizontal or vertical
		 					list.
		 * Return:       	* (HBox or VBox)
		 * Version:   	 	1.0
		 * Compatibility:	1.0
		 */
		public function showWebcamSelector(type:String="list", displayItem:*=undefined):*{
		 	//var cam:settingsWebcamEntry = new assets.settingsWebcamEntry;
		 	//cont.addChild(cam);
		 	
		 	switch(type){
		 		case "list":
		 		default:
		 		
		 		break;
		 		case "dropdown":
		 		
		 		break;
		 	}
		 	
		 	return undefined;
		}
	}
}